#ifndef GUI_INTERNALS_H
    #define GUI_INTERNALS_H

/******************* Internal data *******************************************/
#define DEF_MSGQUEUE_LEN    16
#define SIZE_CLIPRECTHEAP   16
#define SIZE_INVRECTHEAP    32
#define SIZE_QMSG_HEAP      16

#define DEF_NR_TIMERS       32

/******************** Handle type and child type. ***************************/
#define TYPE_HWND           0x01
    #define TYPE_MAINWIN    0x11
    #define TYPE_CONTROL    0x12
    #define TYPE_ROOTWIN    0x13
#define TYPE_HMENU          0x02
    #define TYPE_MENUBAR    0x21
    #define TYPE_PPPMENU    0x22
    #define TYPE_NMLMENU    0x23
#define TYPE_HACCEL         0x03
#define TYPE_HCURSOR        0x05
#define TYPE_HICON          0x07
#define TYPE_HDC            0x08
    #define TYPE_SCRDC      0x81
    #define TYPE_GENDC      0x82
    #define TYPE_MEMDC      0x83

#define TYPE_WINTODEL       0xF1
#define TYPE_UNDEFINED      0xFF


#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

typedef struct _MSGQUEUE MSGQUEUE;
typedef MSGQUEUE* PMSGQUEUE;

// the MSGQUEUE struct is a internal struct.
// using semaphores to implement message queue.
struct _MSGQUEUE
{
    DWORD dwState;              // message queue states

    MSG* msg;                   /* post message buffer */
    int len;                    /* buffer len */
    int readpos, writepos;      /* positions for reading and writing */
};

struct _MAINWIN;
typedef struct _MAINWIN* PMAINWIN;

BOOL InitMsgQueue (PMSGQUEUE pMsgQueue, int iBufferLen);
void DestroyMsgQueue (PMSGQUEUE pMsgQueue);
BOOL QueueMessage (PMSGQUEUE msg_que, PMSG msg);
extern PMAINWIN __lg_active_mainwnd;
extern PMSGQUEUE __lg_dsk_msg_queue;
extern PMAINWIN __lg_dsk_win;
extern HWND __lg_hwnd_desktop;

extern int DesktopWinProc (HWND hWnd,
                int message, WPARAM wParam, LPARAM lParam);

static BOOL QueueDeskMessage (PMSG msg)
{
    msg->hwnd = __lg_hwnd_desktop;
    return QueueMessage (__lg_dsk_msg_queue, msg);
}

typedef struct _ZORDERNODE
{
     HWND hWnd;                     /* Handle of window */

     struct _ZORDERNODE* pNext;     /* Next window */
}ZORDERNODE;
typedef ZORDERNODE* PZORDERNODE;

typedef struct _ZORDERINFO
{
    int nNumber;                    /* Number of windows */

    HWND hWnd;                      /* Handle of host window */

    PZORDERNODE pTopMost;           /* the top most Z order node */
} ZORDERINFO;
typedef ZORDERINFO* PZORDERINFO;

typedef struct _MAINWIN
{
    /*
     * These fields are similiar with CONTROL struct.
     */
    short DataType;     // the data type.
    short WinType;      // the window type.

    int x;
    int y;
    int width;
    int height;
    DWORD dwStyle;      // the styles of main window.


    int (*MainWindowProc)(HWND, int, WPARAM, LPARAM);
                        // the address of main window procedure.

    PZORDERNODE pZOrderNode;

    char* spCaption;    // the caption of main window.
    int   id;           // the identifier of main window.

    struct _MAINWIN* pMainWin;
                        // the main window that contains this window.
                        // for main window, always be itself.

    HWND hParent;       // the parent of this window.
                        // for main window, always be HWND_DESKTOP.

    /*
     * Child windows.
     */
    HWND hFirstChild;    // the handle of first child window.

    PMSGQUEUE pMessages;
                        // the message queue.
} MAINWIN;

BOOL InitGDI (void);
void TerminateGDI (void);


BOOL InitDesktop (void);
void TerminateDesktop (void);

/* return main window contains hWnd. */
PMAINWIN GetMainWindowPtrOfControl (HWND hWnd);
/* check whether hWnd is main window and return pointer to main window hWnd. */
PMAINWIN CheckAndGetMainWindowPtr (HWND hWnd);

MSGQUEUE* InitMsgQueueThisThread (void);
void FreeMsgQueueThisThread (void);

/* hWnd is a window, including HWND_DESKTOP */
#define MG_IS_WINDOW(hWnd)              \
            (hWnd &&                    \
             hWnd != HWND_INVALID &&    \
             ((PMAINWIN)hWnd)->DataType == TYPE_HWND)

/* hWnd is a normal window, not including HWND_DESKTOP */
#define MG_IS_NORMAL_WINDOW(hWnd)       \
        (hWnd != HWND_DESKTOP && MG_IS_WINDOW(hWnd))

/* hWnd is a main window */
#define MG_IS_MAIN_WINDOW(hWnd)         \
        (MG_IS_WINDOW(hWnd) && ((PMAINWIN)hWnd)->WinType == TYPE_MAINWIN)

#define MG_IS_NORMAL_MAIN_WINDOW(hWnd)  \
        (hWnd != HWND_DESKTOP && MG_IS_MAIN_WINDOW(hWnd))

#define MG_GET_WINDOW_PTR(hWnd)   ((PMAINWIN)hWnd)
#define MG_GET_CONTROL_PTR(hWnd)  ((PCONTROL)hWnd)

#define MG_CHECK_RET(condition, ret) \
            if (!(condition)) return ret

#define MG_CHECK(condition) \
            if (!(condition)) return

/* -------------------------------------------------------------------------- */

#ifdef __cplusplus
}
#endif  /* __cplusplus */

#endif // GUI_INTERNALS_H
